/*
 * 2010/8/13 
 *
 * ARM assembly languages note!
 */

'at&t 

/*
 * big endian to little endian
 *
 * big endian r0 = a, b, c, d
 * 
 * little endian r0 = d, c, b, a
 */
eor r1, r0, r0, ror #16					; r1 = a^c, b^d, c^a, d^b
bic r1, r1, #0xff0000					; r1 = a^c, 0, c^a, d^b
mov r0, r0, ror #8						; ro = d, a, b, c
eor r0, r0, r1, lsr #8					; ro = d, c, b, a


/*
 * greatest common divisor C code corresponding Assembly code 
 */

int gcd(int a, int b)
{
	while(a != b)
		if(a > b)
			a = a - b;
		else
			b = b - a;
	return a;
}

gcd
cmp r0, r1			; compare a and b
subgt r0, r0, r1	; if(a > b) a = a - b; (if a == b do nothing)
sublt r1, r1, r0	; if(b > a) a = a - b; (if a == b do nothing)
bne gcd				; if(a!=b) then goto gcd continue execute!
mov pc, lr			; sub route execute over, return ;


/*
 * condition judge 
 */
if(a == 0 || b == 1)
	c = d + e;

; r0 <- a, r1 <- b, code executed r2 save d and e the sum
cmp r0, #0			; judge r0 is whether equal to 0
cmpne r1, #1		; if(r0 != 0) judge r1 whether equal to 1 
addeq r2, r3, r4	; r0 = 1 or r1 = 1, r2 = r3 + r4



example 1:

	if (x = y)
		p = q + r;
	else if (x < y)
		p = q - r;

	cmp r0, r1			; compare x and y
	addeq r2, r3, r4	; if x = y then p = q + r
	subls r2, r3, r4	; else if x < y then p = q -r


example 2:
	
	if (a = b) and (c = d)	then e = e + 1;

	a, b, c, d, e : r0, r1, r2, r3, r4

	cmp r0, r1			; compare a and b
	cmpeq r2, r3		; IF a = b then compare c and d
	addeq r4, r4, #1	;if c = d then increment e by 1

example 3:
	while (a != b) {
		if (a > b)
			a -= b;
		else
			b -= a;
	}

	gcb
		cmp r1, r2
		beq complete
		blt lessthan
		sub r1, r1, r2
		b gcg
	lessthan
		sub r2, r2, r1
		b gcd
	complete
		....


有条件转移:
	如果CPSR的Z-bit是0,跳转

	mov r0, #20		; load the loop counter r0 with 20
	next			; body of loop
	subs r0, r0, #1	; decrement loop counter
	bne next		; repeat until loop count = zero

Data movement memory reference instructions
	从一个register copy 数据到另一个register

	mov r0, #0				; [r0] <- 0; clear r0
	mov r0,r1, lsl #4		; [r0] <- [r1] * 16
	movne r3, r2, asr #5	; IF Z = 0 then [r3] <- [r2]/32
	movs r0, r1, lsl #4		; [r0]<-[r1]*16; update condition codes
	mvn r0, #0				; [r0] <- -1; the 1's complement of 0 is 11111...1
	mvn r0, r0				; [r0] <- [r0]; complement the bits of r0
	mvn r0,#0xf				; [r0] <- 0xFFFFFFF0

	存储器与寄存器交换数据
	ldr r0, [r1]		; load r0 with the word pointed at by r1
	str r2, [r3]		; store the word in r2 in the location pointed at by r3
	ldr r0, [r1, #8]	; effective address = [r1] + 8, r1 is unchanged.
	ldr r0, [r1, #8]!	; effective address = [r1] + 8,  [r1] <- [r1] + 8
	ldr r0, [r1], #8	; effective address = [r1], [r1] <- [r1] + 8

	向量乘
	s = A * B = a1 * b1 + a2 * b2 + a3 * b3 + ... + an * bn

	mov r4, #0			; clear initial sum in r4
	mov r5, #24			; load loop counter with n (assume 24 here)
	adr r0, A			; r0 points at vector A
	adr r1, B			; r1 points at vector B
   next
	ldr r2, [r0], #4	; repeat : get Ai and update pointer to A
	ldr r3, [r1], #4	; get Bi and update pointer to B
	mla r4, r2, r3, r4	; s = s + Ai * Bi
	subs r5, r5, #1		; decrement loop counter
	bne next			; repeat n times


	比较两个16-byte的串
	adr r0, string1		; r0 points to the first string
	adr r1, string2		; r1 points to the second string
	ldmia r0, {r2-r5}	; get first 16-byte string in r2 to r5
	ldmia r1, {r6-r9}	; get second 16-byte string in r6 to r9
	cmp r2, r6			; compare two 4-byte chunks
	cmpeq r3, r7		; if previous 4 bytes same then compare next 4
	cmpeq r4, r8		; and so on
	cmpeq r5, r9
	beq equal			; if final 4 same then strings are equal


/*
 * Link operation
 *
 * 在链表中搜索与某一数据相等的元素.链表的每个元素包括两个字,第1个字中包含一个字节数据;
 * 第2个字包含指向下一个链表元素的指针,当这个指针为0时表示链表结束.代码执行前 R0 指向链表
 * 的头元素, R1 中存放将要搜索的数据:代码执行后 R0 指向第1个匹配的元素,或者当没有匹配元素时,
 * R0 为 0.
 */

llsearch 
	cmp r0, #0				// R0 指针是否为空.
	ldrneb r2, [r0]			// 读取当前元素的字节数据
	cmpne r1, r2			// 判断当前元素中的数据是否为搜索的数据.
	ldrne r0, [r0, #4]		// 如果不是,指针R0指向下一个元素.
	bne llsearch			// 如果下一个元素存在,跳转到llsearch execute
	mov pc, lr				// search over return .



/*
 * 简单的串比较		arm_struct_prog   P120
 *
 * r0 指向第1个串,R1 指向第2个串.代码executed R0 中保存比较结果,如果两个串相同, R0 为 0;
 * 如果第1个串大于第2个串,R0 > 0; 如果第1个串小于第2个串, RO < 1;
 */

strcmp
ldrb r2, [r0], #1		; 从第一个串中读取字节数据到R2中
ldrb r3, [r1], #1		; 从第二个串中读取字节数据到R3中
cmp r2, #0				; 判断第一个串是否已经搜索完了.
cmpne r3, #0			; 判断第二个串是否已经搜索完了.
beq return				; 如果作任一个串搜索完了,跳转到return
cmp r2, r3				; 如果两个串均未搜索完,比较两个串中对应元素
beq strcmp				' 如果两个元素相等,继续比较后面的元素.
return 
sub r0, r2, r3			; 如果两个元素不相等,判断二者大小关系
mov pc, lr				; 程序返回
		

/*
 * Section
 */
"可执行的映象文件通常包括3部分:
1.一个或多个代码段.代码段通常是只读的.
2.零个或多个包含初始值的数据段.这些数据段通常是可读写的.
3.零个或多个不包含初始值的数据段.这些数据段初初始化为0,可读写.

"代码段:存放执行代码.
"数据段:存放代码运行时需要用到的数据.




/*
 * String Copy inline Assembly
 */
void my_strcpy(char *src, const char *dst)
{
	int ch;
	__asm
	{
		loop:
			ldrb ch, [src], #1
			strb ch, [dst], #1
			cmp  ch, #0
			bne  loop
	}
}

int main(void)
{
	const char *a = "Hello World!";
	char b[20];
	__asm
	{
		mov r0, a
		mov r1, b
		bl my_strcpy, {r0, r1}
	}
	printf("Original string: %s\n", a);
	printtf("Copied string: %s \n", b);
	return 0;
}

/* enable and disable interrupt */
__inline void enable_IRQ(void)
{
	int tmp;
	__asm
	{
		mrs tmp, cpsr
		bic tmp, tmp, #0x80
		msr cpsr_c, tmp
	}
}

__inline void disable_IRQ(void)
{
	int tmp;
	__asm
	{
		mrs tmp, cpsr
		orr tmp, tmp, #0x80
		msr cpsr_c, tmp
	}
}

int main(void)
{
	disable_IRQ();
	enable_IRQ();
}

/* 点积操作 */
#define lo64(a) (((unsigned *) &a)[0])		// 取64位数的低32位
#define hi64(a) (((int *) &a)[1]			// 取64位数的高32位
__inline __int64 mlal(__int64 sum, int a, int b)
{
	__asm
	{
		smlal lo64(sum), hi64(sum), a, b
	}
	return sum;
}

__int64 dotprod(int *a, int *b, unsigned n)
{
	__int64 sum = 0;
	do
	{
		sum = mlal(sum, *a++, *b++);
	}
	while (--n != 0);

	return sum;
}

int a[10] = {1,2,3,4,5,6,7,8,9,10};
int b[10] = {10,9,8,7,6,5,4,3,2,1};
int main(void)
{
	printf("Dotproduct %lld (shold be %d) \n", dotprod(a, b, 10), 220);
	return 0;
}


/* C code Inline Assembly Note: 264 */
1.在汇编指令中,逗号(,)用作分隔符.因此如果指令中的C\C++表达式包含有(,),则该表达式应该被包含在括号中.
	__asm { add x, y, {f(), z)}		// (f(), z) 为C\C++表达式.

2.如果在指令中使用的物理寄存器,应该保证该寄存器不会被编译器在计算表达式值时破坏.
__asm
{
	mov r0, x
	add y, r0, x / y 
}
"应改为:
__asm
{
	mov cvar, x
	add y, r0, x / y
}
// C变量代替物理寄存器R0. 编译器将会为变量cvar分配合适的寄存器,从而避免冲突发生.如不能
// 分配合适的寄存器,它将会报告错误.

3.不要使用物理寄存器去引用一个C变量.
int example1(int x)
{
	__asm
	{
		add r0, r0, #1
	}
	return x;
}
// 正确写法
int exmaple(int x)
{
	__asm
	{
		add x, x, #1
	}
	return x;
}

4.对于内嵌汇编器可能会用到的寄存器,编译器自己会保存和恢复这引起寄存器,用户不用保存和恢复这些寄存器.
  常量寄存器CPSR 和寄存器 SPSR 外,别的寄存器必须先赋值然后再读取,否则编译器将会报错.
int f(int x)
{
	__asm
	{
		stmfd sp!, [r0]			// 没有给寄存器R0赋值前读取其值.
		add   r0, x, 1
		eor   x, r0, x
		ldmfd sp!, [r0]			// 没有必要恢复寄存器R0的值.
	}
}


/* 汇编访问C变量 */
unsigned char == ldrb/strb	;
unsigned short == ldrh/strh ;
int			   == ldr/str	;
char		   == ldrsb/strb;
short          == ldrsh/strh;


/* access globe var */
area globals, CODE, READONLY	;
EXPORT asmsub					;
import globl					; 用IMPORT声明该变量
asmsub	
ldr r1, ==globv1				; 将其内存地址读入到寄存器
ldr r0, [r1]					; 再将其值读入到寄存器R0
add r0, r0, #2					; 
str r0, [r1]					; 修改后再将寄存器R0的值赋予变量globv1
mov pc, lr
end




/* M 地址对换  */
512K  = 0x00080000;

lM    = 0x00100000;				/* 5 zero */
2M    = 0x00200000;
3M    = 0x00300000;
4M    = 0x00400000;
8M    = 0x00800000;

16M   = 0x01000000;				/* 6 zero */
17M   = 0x01100000;
18M   = 0x01200000;

32M   = 0x02000000;
64M   = 0x04000000;
128M  = 0x08000000;

256M  = 0x10000000;				/* 7 zero */				
512M  = 0x20000000;
1024M = 0x40000000;



/*
 *  
 */
